home *** CD-ROM | disk | FTP | other *** search
/ Libris Britannia 4 / science library(b).zip / science library(b) / PROGRAMM / DB_CLIPP / 0277.ZIP / USQ2.C < prev    next >
Text File  |  1986-02-28  |  20KB  |  933 lines

  1. static char *sccsid = "@(#)usq2.c       1.9u (UCF) 13/02/86";
  2. /*
  3.  *     THIS IS THE SOURCE CODE FOR USQ2.C.
  4.  *
  5.  *    usq.c - CP/M compatible multi-disk file unsqueezer utility
  6.  *
  7.  */
  8.  
  9. /*    modified by J. Chappell 02-02-84 to check if ferror occurred on write
  10.                 02-07-84 to accept wildcards in filenames
  11.                 07-01-86 to match sq2.c (Ark - v1.9u)
  12.                 13-02-86 for CP/M86 and MSC
  13. */
  14.  
  15. #include <stdio.h>
  16. #include <string.h>
  17. #include <ctype.h>
  18.  
  19. #ifdef CPMC86
  20. #define strupr    upper
  21. #endif
  22.  
  23. #ifdef MSDC86
  24. #include <time.h>
  25. #endif
  26.  
  27. #ifdef MSDMSC
  28. #include <time.h>
  29. #include <dos.h>
  30. #include <fcntl.h>
  31. #include <sys\types.h>
  32. #include <sys\stat.h>
  33. #include <io.h>
  34. #define BWRITE    O_RDWR|O_CREAT|O_BINARY
  35. #define BPERMS    S_IREAD|S_IWRITE
  36. #define BREAD    O_RDONLY|O_BINARY
  37. #endif
  38.  
  39. #define VERSION "1.9u   14-02-86"
  40.  
  41. #define TRUE 1
  42. #define FALSE 0
  43. #define ERROR (-1)
  44. #define PATHLEN 64    /* Number of characters allowed in pathname */
  45. #define OK 0
  46.  
  47. #define RECOGNIZE 0xFF76    /* unlikely pattern */
  48. #define DLE 0x90        /* repeat byte flag */
  49. #define SPEOF 256        /* special endfile token */
  50. #define NUMVALS 257        /* 256 data values plus SPEOF*/
  51. #define LARGE 30000
  52.  
  53. typedef int INT;
  54. typedef unsigned UNSIGNED;
  55.  
  56. struct _sqleaf {        /* Decoding tree */
  57.     INT _children[2];    /* left, right */
  58. };
  59. struct _sqleaf Dnode[NUMVALS - 1];
  60.  
  61.  
  62. INT Bpos;        /* last bit position read */
  63. INT Curin;        /* last byte value read */
  64. INT Repct;        /* Number of times to return value */
  65. INT Value;        /* current byte value or EOF */
  66.  
  67. INT MakeLCPathname=TRUE;    /* translate pathname to lc if all caps */
  68. INT Nlmode=FALSE;        /* zap cr's if true */
  69. INT Inbackground = FALSE;
  70. INT getcr(), getuhuff(), portgetw();
  71.  
  72. /* new globals for version 1.9u
  73.    ---------------------------- */
  74. int dcount = 0;
  75. int fcount = 0;
  76. long free_space = 0L;
  77. long old_date;
  78. INT bkup_id = 0;
  79. INT span_cnt = 0;
  80. char src_drv[20];
  81. char tgt_fils[PATHLEN+2];
  82. unsigned char outfile[PATHLEN+2];    /* output file spec. */
  83. unsigned char infile[PATHLEN+2];
  84. FILE *in, *out;
  85. char tgt_path[PATHLEN+2], src_path[PATHLEN+2], src_name[16];
  86. char origname[PATHLEN];         /* Original file name without drive */
  87. char *first, *next;
  88.  
  89. #define SPAN_CHR    0xff        /* marks incomplete restore/file */
  90. #define FIN_CHR     0x00        /* marks last disk/last segment */
  91.  
  92. /* structure of SQZID.@@@ */
  93.  
  94. struct bki {
  95.     unsigned char bk_fflag;        /* FF=middle disk 00=last disk */
  96.     int       bk_seqn;        /* disk sequence number */
  97.     long      bk_date;        /* backup date in long format - seconds since 01.01.70 */
  98.     char      bk_spare[121];
  99.     } bkid;
  100.  
  101. /* structure of SQUEEZED file header */
  102.  
  103. struct sqh {
  104.     unsigned char sq_fflag;        /* FF=incomplete 00=last segment */
  105.     int       sq_span;        /* span count */
  106.     int       sq_nulo;
  107.     char      sq_path[65];        /* path + filename */
  108.     char      sq_spare[58];     /* spare */
  109.     } sqid;
  110.  
  111. FILE *fopen();
  112.  
  113. main(argc, argv)
  114. unsigned char *argv[];
  115. {
  116.     char *ptr;
  117.     int errorstat;
  118.  
  119.     if(argc != 3)
  120.     usage();
  121.  
  122.     /* get the source drive - limited to A or B */
  123.     strcpy(src_drv, argv[1]);
  124.     strupr(src_drv);
  125.     if(src_drv[0] > 'B' || src_drv[0] < 'A' || src_drv[1] != ':' || hasbad(src_drv))
  126.     abort("\007usq2: source drive must be drive A: or drive B:");
  127.  
  128.     /* get the target files and check that they are not the same drive */
  129.     strcpy(tgt_fils, argv[2]);
  130.     strupr(tgt_fils);
  131.     if(strchr(tgt_fils,':') != NULL && (src_drv[0] == tgt_fils[0]))
  132.     abort("\007usq2: source and destination drives are the same!\n\n");
  133.  
  134.     /* convert all '/' to '\' */
  135.     for(ptr = tgt_fils; *ptr; ptr++)
  136.     if(*ptr == '/')
  137.         *ptr = '\\';
  138.  
  139.  
  140.     /* now isolate the path */
  141.     get_path(tgt_fils, tgt_path);
  142.  
  143.     /* now make the path, if neccesary, on the target */
  144.     if(mak_path(tgt_fils) == EOF)
  145.     {
  146.     fprintf(stderr, "\007usq2: can't make path for %s\n", tgt_fils);
  147.     exit(1);
  148.     }
  149.  
  150.     errorstat=0;
  151.  
  152.     for(;;)
  153.     {
  154.     new_disk();
  155.     if(first == NULL)
  156.         {
  157.         if(bkid.bk_fflag == '\0')
  158.         break;
  159.         else
  160.         continue;
  161.         }
  162.     do
  163.         {
  164.         strcpy(src_name, src_drv);
  165.         strcat(src_name,next);
  166.         errorstat |= squeeze();
  167.         next = next + strlen(next) + 1;
  168.         }
  169.         while(*next != '\0');
  170.  
  171.     if(!haswild(tgt_fils) && sqid.sq_fflag == '\0')
  172.         break;
  173.     if(bkid.bk_fflag == '\0')
  174.         break;
  175.     }
  176.     exit(errorstat != 0);
  177. }
  178.  
  179. /* log in a new disk */
  180.  
  181. new_disk()
  182. {
  183.     int bk;
  184.     char src[20], *d_ptr;
  185.     char *filedir();
  186.  
  187.     if(++bkup_id != 1 && first != NULL)
  188.     free(first);
  189.  
  190.     if(sqid.sq_fflag == SPAN_CHR && bkup_id != 1)
  191.     {
  192.     fclose(in);
  193.     }
  194.  
  195.     for(;;)
  196.     {
  197.     fprintf(stderr,"\n\n%cInsert restore diskette %02d in drive %s\n",'\007',bkup_id, src_drv);
  198.     fprintf(stderr,"Strike any key when ready... ");
  199.     bdos(1,0);
  200.     dsk_reset(src_drv);
  201.     if((bk = get_bkupid(src_drv)) < 0)
  202.         {
  203.         fprintf(stderr,"\n\n%cERROR - not a restore diskette in drive %s\n",'\007', src_drv);
  204.         fprintf(stderr,"Strike any key when ready... ");
  205.         bdos(1,0);
  206.         continue;
  207.         }
  208.     if(dcount == 0)
  209.         old_date = bkid.bk_date;
  210.     else
  211.         if(old_date != bkid.bk_date)
  212.         {
  213.         fprintf(stderr,"\n\n%cERROR - different backup date on restore diskette in drive %s \n",'\007', src_drv);
  214.         fprintf(stderr,"Strike any key when ready... ");
  215.         bdos(1,0);
  216.         continue;
  217.         }
  218.     if(bk != bkup_id)
  219.         {
  220.         fprintf(stderr,"\n\n%cRestore diskette %02d in drive %s is out of sequence\n",'\007',bk, src_drv);
  221.         fprintf(stderr,"Strike any key when ready... ");
  222.         bdos(1,0);
  223.         if(dcount == 0)
  224.         {
  225.         bkup_id = bk;
  226.         }
  227.         else
  228.         continue;
  229.         }
  230.  
  231.     fprintf(stderr,"\n\n*** Unsqueezing files from diskette %02d ***\n",bkup_id);
  232.     strcpy(src,src_drv);
  233.     if((d_ptr = strrchr(tgt_fils, '\\')) != NULL)
  234.         strcat(src, ++d_ptr);
  235.     else if((d_ptr = strrchr(tgt_fils, '/')) != NULL)
  236.         strcat(src, ++d_ptr);
  237.     else if((d_ptr = strrchr(tgt_fils, ':')) != NULL)
  238.         strcat(src, ++d_ptr);
  239.     else
  240.         strcat(src, tgt_fils);
  241.     first = filedir(src,0);
  242.     next = first;
  243.     dcount++;
  244.     break;
  245.     }
  246.  
  247.     /* skip first entry - SQZID.@@@ */
  248.     if(strcmp(next, "SQZID.@@@") == 0)
  249.     next = next + strlen(next) + 1;
  250.  
  251.     if(sqid.sq_fflag == SPAN_CHR && bkup_id != 1)
  252.     {
  253.     if((in=fopen(src_name, "rb"))==NULL)
  254.         {
  255.         fprintf(stderr, "\n\n%cERROR - can't open %s - SEQUENCE\n", '\007',src_name);
  256.         exit(1);
  257.         }
  258.  
  259.     /* get squeeze "RESTORE" header and make sure we have right part of file */
  260.     get_sqhdr();
  261.     if(sqid.sq_span != ++fcount)
  262.         {
  263.         fclose(in);
  264.         fprintf(stderr,"\n\n%cERROR - file %s out of sequence\n\n",'\007',src_name);
  265.         exit(1);
  266.         }
  267.  
  268.     /* now check that we have the same path */
  269.     strupr(sqid.sq_path);
  270.     get_path(sqid.sq_path,src_path);
  271.     if((d_ptr = strchr(tgt_path, ':')) != NULL)
  272.         d_ptr++;
  273.     else
  274.         d_ptr = &tgt_path[0];
  275.  
  276.     if(strcmp(src_path, d_ptr) != 0)
  277.         {
  278.         fclose(in);
  279.         fprintf(stderr,"\n\n%cERROR - file %s out of sequence\n\n",'\007',src_name);
  280.         exit(1);
  281.         }
  282.     if (!Inbackground)
  283.         fprintf(stderr, "usq2: %s -> %s\n",src_name,origname);
  284.     }
  285.  
  286.     return(TRUE);
  287. }
  288.  
  289. get_bkupid(drive)
  290. char *drive;
  291. {
  292.     char filespec[16];
  293.     int fd;
  294.  
  295.     strcpy(filespec,drive);
  296.     strcat(filespec,"SQZID.@@@");
  297.     if((fd = open(filespec,BREAD)) < 0)
  298.     return(fd);
  299.     read(fd,&bkid,sizeof(bkid));
  300.     close(fd);
  301.     return( (int) (bkid.bk_seqn));
  302. }
  303.  
  304. /*
  305.     The following code is primarily from typesq.c and utr.c.  Typesq
  306. is a modification of USQ by Dick Greenlaw.  Those modifications (usq
  307. to typesq) were made by Bob Mathias, I am responsible for the butchery
  308. done to make it work with cat.
  309.  
  310. */
  311.  
  312.  
  313. squeeze()
  314. {
  315.     register INT i, c;
  316.     register unsigned char *p;
  317.     register INT numnodes;            /* size of decoding tree */
  318.     register UNSIGNED crc;
  319.     UNSIGNED filecrc;
  320.     char *d_ptr;
  321.  
  322.     init_cr();
  323.     init_huff();
  324.     crc=0;
  325.     fcount = 0;
  326.  
  327.     if((in=fopen(src_name, "rb"))==NULL)
  328.     {
  329.     fprintf(stderr, "\007usq2: can't open %s\n", src_name);
  330.     return ERROR;
  331.     }
  332.  
  333.     /* get squeeze "RESTORE" header and make sure we have first part of file */
  334.     get_sqhdr();
  335.     if(sqid.sq_span != 0)
  336.     {
  337.     fclose(in);
  338.     fprintf(stderr,"\n\n%cERROR - file %s out of sequence\n\n",'\007',src_name);
  339.     exit(1);
  340.     }
  341.  
  342.     /* now check that we have the same path */
  343.     strupr(sqid.sq_path);
  344.  
  345.     get_path(sqid.sq_path,src_path);
  346.     if((d_ptr = strchr(tgt_path, ':')) != NULL)
  347.     d_ptr++;
  348.     else
  349.     d_ptr = &tgt_path[0];
  350.  
  351.     if(strcmp(src_path, d_ptr) != 0)
  352.     {
  353.     fclose(in);
  354.     return(OK);
  355.     }
  356.  
  357.     /* now process "SQUEEZE" header */
  358.     if(portgetw(in) != (INT) RECOGNIZE)     /* Process header */
  359.     {
  360.     fprintf(stderr, "\007usq2: %s is not a SQueezed file\n", src_name);
  361.     fclose(in);
  362.     return(ERROR);
  363.     }
  364.     filecrc = (UNSIGNED) portgetw(in);        /* checksum */
  365.  
  366.     numnodes = portgetw(in);
  367.     if(numnodes < 0 || numnodes >= NUMVALS)
  368.     {
  369.     fprintf(stderr, "\007usq2: %s has invalid decode tree\n", src_name);
  370.     fclose(in);
  371.     return(ERROR);
  372.     }
  373.  
  374.     /* Initialize for possible empty tree (SPEOF only) */
  375.     Dnode[0]._children[0] = -(SPEOF + 1);
  376.     Dnode[0]._children[1] = -(SPEOF + 1);
  377.  
  378.     /* Get decoding tree from file */
  379.     for(i = 0; i < numnodes; ++i)
  380.     {
  381.     Dnode[i]._children[0] = portgetw(in);
  382.     Dnode[i]._children[1] = portgetw(in);
  383.     }
  384.  
  385.     /* now make target filename */
  386.     strcpy(origname,tgt_path);
  387.     strcat(origname,next);
  388.  
  389.     /* Get translated output bytes and write file */
  390.     if (!Inbackground)
  391.     fprintf(stderr, "usq2: %s -> %s\n",src_name,origname);
  392.     if((out=fopen(origname, "wb"))==NULL)
  393.     {
  394.     fprintf(stderr, "\007usq2: can't create %s\n", origname);
  395.     fclose(in);
  396.     return(ERROR);
  397.     }
  398.  
  399.     /* decode file */
  400.     while ((c = getcr()) != EOF)
  401.     {
  402.     crc += (UNSIGNED) c;
  403.     if(fputc(c,out)!=c)
  404.         {
  405.         fclose(in);
  406.         fclose(out);
  407. #ifdef MSDMSC
  408.         fprintf(stderr,"\007usq2: error in writing file: %s\n",origname);
  409.         exit(1);
  410. #else
  411.         abort("\007usq2: error in writing file: %s\n",origname);
  412. #endif
  413.         }
  414.     }
  415.     fclose(in);
  416.  
  417.     if(fflush(out)<0 || ferror(out)<0)
  418.     abort("\007usq2: Error writing file: %s\n",origname);
  419.     if(fclose(out)<0)
  420.     abort("\007usq2: Error closing file: %s\n",origname);
  421.  
  422.     if( crc != filecrc )
  423.     {
  424.     fprintf(stderr, "\007usq2: bad checksum in %s\n", src_name);
  425.     fflush(stdout);
  426.     return(ERROR);
  427.     }
  428.     return(OK);
  429. }
  430.  
  431. /*** from utr.c - */
  432. /* initialize decoding functions */
  433.  
  434. init_cr()
  435. {
  436.     Repct = 0;
  437. }
  438.  
  439. init_huff()
  440. {
  441.     Bpos = 99;    /* force initial read */
  442. }
  443.  
  444. /* Get bytes with decoding - this decodes repetition,
  445.  * calls getuhuff to decode file stream into byte
  446.  * level code with only repetition encoding.
  447.  *
  448.  * The code is simple passing through of bytes except
  449.  * that DLE is encoded as DLE-zero and other values
  450.  * repeated more than twice are encoded as value-DLE-count.
  451.  */
  452.  
  453. INT getcr()
  454. {
  455.     register INT c;
  456.  
  457.     if(Repct > 0)
  458.     {
  459.     /* Expanding a repeated char */
  460.     --Repct;
  461.     return(Value);
  462.     }
  463.     else
  464.     {
  465.     /* Nothing unusual */
  466.     if((c = getuhuff()) != DLE)
  467.         {
  468.         /* It's not the special delimiter */
  469.         Value = c;
  470.         if(Value == EOF)
  471.         Repct = LARGE;
  472.         return(Value);
  473.         }
  474.     else
  475.         {
  476.         /* Special token */
  477.         if((Repct = getuhuff()) == 0)
  478.         /* DLE, zero represents DLE */
  479.         return(DLE);
  480.         else
  481.         {
  482.         /* Begin expanding repetition */
  483.         Repct -= 2;    /* 2nd time */
  484.         return(Value);
  485.         }
  486.         }
  487.     }
  488. }
  489.  
  490. /* Decode file stream into a byte level code with only
  491.  * repetition encoding remaining.
  492.  */
  493.  
  494. INT
  495. getuhuff()
  496. {
  497.     register INT i;
  498.  
  499.     /* Follow bit stream in tree to a leaf*/
  500.     i = 0;                    /* Start at root of tree */
  501.     do
  502.     {
  503.     if(++Bpos > 7)
  504.         {
  505.         if((Curin = getc(in)) == ERROR)
  506.         {
  507.         if(sqid.sq_fflag == SPAN_CHR)
  508.             {
  509.             new_disk();
  510.             Curin = getc(in);
  511.             }
  512.         else
  513.             return(ERROR);
  514.         }
  515.  
  516.         Bpos = 0;
  517.  
  518.         /* move a level deeper in tree */
  519.         i = Dnode[i]._children[1 & Curin];
  520.         }
  521.     else
  522.         i = Dnode[i]._children[1 & (Curin >>= 1)];
  523.     } while(i >= 0);
  524.  
  525.     /* Decode fake node index to original data value */
  526.     i = -(i + 1);
  527.     /* Decode special endfile token to normal EOF */
  528.     i = (i == SPEOF) ? EOF : i;
  529.     return(i);
  530. }
  531.  
  532. /*
  533.  * Machine independent getw which always gets bytes in the same order
  534.  *  as the CP/M version of SQ wrote them
  535.  */
  536.  
  537. INT
  538. portgetw(f)
  539. FILE *f;
  540. {
  541.     register INT c, result;
  542.  
  543.     if((c = getc(f)) == EOF)
  544.         {
  545.         new_disk();
  546.         c = getc(f);
  547.         }
  548.     result = c & 0377;
  549.     if((c = getc(f)) == EOF)
  550.         {
  551.         new_disk();
  552.         c = getc(f);
  553.         }
  554.     result |= (c << 8);
  555.     return(result);
  556. }
  557.  
  558.  
  559. /* make string s lower case */
  560. uncaps(s)
  561. unsigned char *s;
  562. {
  563.     for( ; *s; ++s)
  564.         if(isupper(*s))
  565.             *s = tolower(*s);
  566. }
  567.  
  568.  
  569. /*
  570.  * IsAnyLower returns TRUE if string s has lower case letters.
  571.  */
  572. IsAnyLower(s)
  573. unsigned char *s;
  574. {
  575.     for( ; *s; ++s)
  576.         if (islower(*s))
  577.             return(TRUE);
  578.     return(FALSE);
  579. }
  580.  
  581. usage()
  582. {
  583.     fprintf(stderr,"\n\nFile unsqueezer version %s by\n\n\tRichard Greenlaw\n\t251 Colony Ct.\n\tGahanna, Ohio 43230\n", VERSION);
  584.     fprintf(stderr,"\n\tMulti-disk version by Ark Software for the Public Domain");
  585.     fprintf(stderr,"\n\t     **this program is free and not for sale**\n\n");
  586.     fprintf(stderr,"Usage: usq2 <source drive> <target files>\n\n");
  587.     fprintf(stderr,"\tie. usq2 a: c:\\subdir\\*.*\n\n");
  588.     exit(1);
  589. }
  590.  
  591. hasbad(trg)
  592. char *trg;
  593.  
  594. {
  595.     char c;
  596.  
  597.     while (c = *trg++)
  598.     if (c == '*' || c == '?' || c == '.' || c == '\\' || c == '/')
  599.         return TRUE;
  600.     return FALSE;
  601. }
  602.  
  603. haswild(trg)
  604. char *trg;
  605. {
  606.     if(strchr(trg,'?') != NULL || strchr(trg,'*') != NULL)
  607.     return TRUE;
  608.     else
  609.     return FALSE;
  610. }
  611.  
  612. get_path(src, tgt)
  613. char *src, *tgt;
  614. {
  615.     char *d_ptr;
  616.  
  617.     strcpy(tgt, src);
  618.  
  619.     /* remove file name */
  620.     if((d_ptr = strrchr(tgt,'\\')) != NULL)
  621.     *++d_ptr = '\0';
  622.     else if((d_ptr = strrchr(tgt, '/')) != NULL)
  623.     *++d_ptr = '\0';
  624.     else if((d_ptr = strrchr(tgt, ':')) != NULL)
  625.     *++d_ptr = '\0';
  626.     else
  627.  
  628. #ifdef CPMC86
  629.     *tgt = '\0';
  630. #else
  631.     strcpy(tgt, "\\");
  632. #endif
  633. }
  634.  
  635. /* read "RESTORE" header */
  636.  
  637. get_sqhdr()
  638. {
  639.     long fseek();
  640.  
  641.     fseek(in,0L,0);
  642.     return(fread(&sqid,sizeof(sqid),1,in));
  643. }
  644.  
  645. /* mak_path() - make subdir(s) if neccesary */
  646.  
  647. #ifdef CPMC86
  648.  
  649. mak_path(org_name)
  650. char *org_name;
  651. {
  652.     return(0);
  653. }
  654.  
  655. #else
  656.  
  657. mak_path(org_name)
  658. char *org_name;
  659. {
  660.     char fil_nam[PATHLEN+2];
  661.     char *fst, *beg_pos, *end_pos;
  662.  
  663.     strcpy(fil_nam, org_name);
  664.     beg_pos = strchr(fil_nam, '\\');
  665.     while(beg_pos != NULL)
  666.     {
  667.     if((end_pos = strchr(beg_pos + 1, '\\')) != NULL)
  668.         {
  669.         *end_pos = '\0';
  670.         if((fst = filedir(fil_nam,0x10)) == NULL)
  671.         {
  672.         if(mkdir(fil_nam) == EOF)
  673.             return(EOF);
  674.         else
  675.             ;
  676.         }
  677.         else
  678.         {
  679.         free(fst);
  680.         }
  681.         *end_pos = '\\';
  682.         }
  683.     beg_pos = end_pos;
  684.     }
  685.     return(0);
  686. }
  687.  
  688. #endif
  689.  
  690. /*    get file directory
  691. */
  692.  
  693. #ifdef MSDMSC
  694.  
  695. unsigned char *malloc();
  696. unsigned char *realloc();
  697.  
  698. struct ff_str {
  699.   char dummy[21];        /* reserved for dos */
  700.   unsigned char attribute;    /* returned attribute */
  701.   unsigned time;
  702.   unsigned date;
  703.   long size;            /* size of file */
  704.   unsigned char fn[13];     /* string containing the filename */
  705. };
  706.  
  707. char *filedir(filename,mode)
  708. unsigned char *filename;
  709. unsigned mode;
  710. {
  711.     union REGS srvi, srvo;
  712.     struct SREGS segregs;
  713.     unsigned int ds, dx;
  714.     struct ff_str ff_area;
  715.     unsigned char *result;
  716.     int reslen=0;
  717.  
  718. #ifdef M_I86LM                    /* large model ? */
  719.     ds = FP_SEG(filename);
  720.     dx = FP_OFF(filename);
  721. #else
  722.     segread(&segregs);                /* get ds value */
  723.     dx = (unsigned) filename;
  724.     ds = segregs.ds;
  725. #endif
  726.  
  727.     srvi.x.dx = (unsigned int) &ff_area;     /* set DTA */
  728.     srvi.h.ah = 0x1a;
  729.     intdosx(&srvi, &srvo, &segregs);
  730.  
  731.     srvi.x.cx = mode;                 /* set search modes */
  732.     srvi.h.ah = 0x4e;                 /* find first */
  733.     srvi.x.dx = dx;
  734.     segregs.ds = ds;
  735.     intdosx(&srvi, &srvo, &segregs);
  736.     if(srvo.x.cflag)
  737.     return(NULL);
  738.     if((result = malloc(strlen(ff_area.fn) + 1)) == NULL)
  739.     return(result);
  740.     reslen = strlen(ff_area.fn) + 1;
  741.     strcpy(result, ff_area.fn);
  742.  
  743.     srvi.h.ah = 0x4f;                /* find next */
  744.     for(;;)
  745.     {
  746.     segregs.ds = ds;
  747.     intdosx(&srvi, &srvo, &segregs);
  748.     if(srvo.x.cflag)
  749.         {
  750.         result = realloc(result, reslen + 1);
  751.         if(result != NULL)
  752.         *(result + reslen) = '\0';
  753.         return(result);
  754.         }
  755.     result=realloc(result,reslen+strlen(ff_area.fn)+1);
  756.     if(result==NULL)
  757.         return NULL;            /* no memory left */
  758.     strcpy(result+reslen,ff_area.fn);
  759.     reslen += (strlen(ff_area.fn) + 1);
  760.     }
  761. }
  762.  
  763. #endif
  764.  
  765. #ifdef CPMC86
  766.  
  767. unsigned char *malloc();
  768. unsigned char *realloc();
  769.  
  770. char *filedir(filename,mode)
  771. unsigned char *filename;
  772. int mode;
  773. {
  774.     char fcb[36];
  775.     char tmpfile[30];
  776.     char dma[128];
  777.     struct { unsigned int ax,bx,cx,dx,si,di,ds,es;} srvi, srvo;
  778.     struct { unsigned int scs, sss, sds, ses;} segs;
  779.     unsigned int dataseg, fcboff;
  780.     unsigned char *result;
  781.     int reslen;
  782.     int i;
  783.  
  784.     reslen = 0;
  785.     segread(&segs);                 /* get ds value */
  786.  
  787.     fcboff = (unsigned) &fcb[0];         /* get fcb offset */
  788.     dataseg = segs.sds;
  789.  
  790.     srvi.dx = (unsigned int) &dma[0];         /* set DMA */
  791.     srvi.cx = 0x001a;                 /* set offset */
  792.     sysint(224, &srvi, &srvo);
  793.     srvi.dx = dataseg;
  794.     srvi.cx = 0x0033;                 /* set segment */
  795.     sysint(224, &srvi, &srvo);
  796.  
  797.     srvi.cx = 0x0011;                 /* find first */
  798.     srvi.dx = fcboff;
  799.     srvi.ds = dataseg;
  800.     if(!setfcb(fcb, filename))
  801.     {
  802.     return(NULL);
  803.     }
  804.     sysint(224, &srvi, &srvo);
  805.     if((srvo.ax & 0x00ff) == 255)
  806.     {
  807.     return(NULL);
  808.     }
  809.     hackname(tmpfile, dma + (srvo.ax * 32));
  810.  
  811.     if((result = malloc(strlen(tmpfile) + 1)) == NULL)
  812.     return(result);
  813.     reslen = strlen(tmpfile) + 1;
  814.     strcpy(result, tmpfile);
  815.  
  816.     srvi.cx = 0x0012;                /* find next */
  817.     for(;;)
  818.     {
  819.     sysint(224, &srvi, &srvo);
  820.     if(srvo.ax == 255)
  821.         {
  822.         result = realloc(result, reslen + 1);
  823.         if(result != NULL)
  824.         *(result + reslen) = '\0';
  825.         return(result);
  826.         }
  827.     hackname(tmpfile, dma + (srvo.ax * 32));
  828.     result=realloc(result,reslen+strlen(tmpfile)+1);
  829.     if(result==NULL)
  830.         return NULL;            /* no memory left */
  831.     strcpy(result+reslen,tmpfile);
  832.     reslen += (strlen(tmpfile) + 1);
  833.     }
  834. }
  835.  
  836. hackname(dest,source)
  837. char *dest, *source;
  838. {
  839.     int i,j;
  840.  
  841.     j = 0;
  842.  
  843.     for (i = 1; i < 9; i++)
  844.     {
  845.         if (source[i] == ' ') break;
  846.         dest[j++] = source[i];
  847.     }
  848.     if (source[9] != ' ')
  849.         dest[j++] = '.';
  850.  
  851.     for (i = 9; i < 12; i++)
  852.     {
  853.         if (source[i] == ' ') break;
  854.         dest[j++] = source[i];
  855.     }
  856.     dest[j] = '\0';
  857.     return dest;
  858. }
  859.  
  860. setfcb(fcb,fname)
  861. char *fcb, *fname;
  862. {
  863.     char *fcb_ptr, *makefcb();
  864.     int i;
  865.     int qflg =0;
  866.  
  867.     if((fcb_ptr = makefcb(fname)) == NULL)
  868.         return(0);
  869.     movmem(fcb_ptr, fcb, 36);
  870.     free(fcb_ptr);
  871.     for(i=1; i<12;i++)
  872.         {
  873.         if(fcb[i] == '*')
  874.         {
  875.         qflg = 1;
  876.         fcb[i] = '?';
  877.         continue;
  878.         }
  879.         if(qflg)
  880.         {
  881.         if(fcb[i] != ' ')
  882.             {
  883.             qflg =0;
  884.             continue;
  885.             }
  886.         fcb[i] = '?';
  887.         }
  888.         }
  889.     return(1);
  890. }
  891.  
  892. #endif
  893.  
  894. #ifdef CPMC86
  895.  
  896. dsk_reset(drv)                    /* oh how I love CP/M!! */
  897. char *drv;
  898. {
  899.     struct { unsigned int ax,bx,cx,dx,si,di,ds,es;} srvi, srvo;
  900.     unsigned int vector;
  901.     int drvno;
  902.  
  903.     drvno = toupper(*drv) - 65;
  904.     vector = 0x0001;
  905.     if(drvno != 0)
  906.     vector <<= drvno;
  907.     srvi.dx = vector;
  908.     srvi.cx = 0x0025;                /* disk reset fn */
  909.     sysint(224, &srvi, &srvo);
  910.     return(srvo.ax);
  911. }
  912.  
  913. #else
  914.  
  915. dsk_reset(drv)
  916. char *drv;
  917. {
  918.     return(0);
  919. }
  920.  
  921. #endif
  922.  
  923. #ifdef MSDMSC
  924. abort(string)
  925. char *string;
  926. {
  927.     fprintf(stderr,"\n\n%s\n\n", string);
  928.     exit(1);
  929. }
  930. #endif
  931.  
  932.  
  933.